//== GAIA ============================================================================

//== BEGINNING OF CODE ===============================================================

#include "sagittarius/core/SagittariusCore.h"

//#include "/home/odin/myhome/downloads/llvm/3.1-release/gnubuild/include/llvm/Support/DataTypes.h"
//#include "C:/Users/odin/Downloads/llvm/3.1-release/xllvm-3.1-build/include/llvm/Support/DataTypes.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
//#include "llvm/ModuleProvider.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/JIT.h"
//#include "llvm/ExecutionEngine/Interpreter.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/LLVMContext.h"
//#include "llvm/Type.h"
//#include "llvm/Target/TargetData.h"
//#include "llvm/Transforms/Scalar.h"
//#include "llvm/Support/IRBuilder.h"
#include "llvm/Support/TargetSelect.h"

#include <iostream>
#include <stdio.h>

static llvm::Module *M;
static llvm::ExecutionEngine *EE;

extern "C" void printHelloWorld() {
    printf("Hello world, main code\n");
}

int main(int argc, char* argv[])
{
    llvm::InitializeNativeTarget();
    llvm::LLVMContext &Context = llvm::getGlobalContext();
    // Make the module, which holds all the code.
    M = new llvm::Module("my cool jit", Context);
    //create jit
    //llvm::ExistingModuleProvider* MP = new llvm::ExistingModuleProvider(M);
    llvm::ExecutionEngine* EE = llvm::ExecutionEngine::create(M, false);
    
    /*FunctionType *FT = FunctionType::get(llvm::Type::getVoidTy(llvm::getGlobalContext()), 
                                         llvm::ArrayRef(),*/
    //llvm::Function* F = M->getOrInsertFunction("funHelloWorld", llvm::Type::getVoidTy(llvm::getGlobalContext()), (llvm::Type *)0);
    llvm::Function* F = llvm::cast<llvm::Function>(M->getOrInsertFunction("funHelloWorld", llvm::Type::getVoidTy(llvm::getGlobalContext()), NULL));
    
    EE->addGlobalMapping(F, (void*)(&printHelloWorld));
    //run function
    std::vector<llvm::GenericValue> noargs;
    //llvm::GenericValue gv = EE->runFunction(F, noargs);
    EE->runFunction(F, noargs);
    
    delete EE;
    //delete M; //do we need this? I think LLVM takes care of it
    //llvm::llvm_shutdown();
    return 0;
}
